﻿module Sustainalytics.News {

    import Common = Sustainalytics.Common;

    // News Add controller
    export class NewsAddController {

        // specifies whether current controller is in loading state
        public isLoading: boolean;

        // controller scope
        public $scope: ng.IScope;

        // news data currently being edited
        public newsData: NewsDto;

        // services
        private $http: ng.IHttpService;
        private $q: ng.IQService;
        private $location: ng.ILocationService;
        private newsAvailabilityService: NewsAvailabilityService;
        private newsCategoryService: NewsCategoryService;
        private newsRegionService: NewsRegionService;
        private newsService: NewsService;
        private newsStatusService: NewsStatusService;
        private notificationFactory: INotificationFactory;
        private staticObjects: IStaticObjects;

        // news availabilities
        public newsAvailabilitiesDic: any;
        public newsAvailabilities: NewsAvailability[];
        // news categories
        public newsCategoriesDic: any;
        public newsCategories: NewsCategory[];
        // news regions
        public newsRegionsDic: any;
        public newsRegions: NewsRegion[];
        // news statuses
        public newsStatusesDic: any;
        public newsStatuses: NewsStatus[];

        public isDateCreatedOpened: boolean;
        public isUnpublishedDateOpened: boolean;


        // Ctor.
        constructor($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, $http: ng.IHttpService, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory: INotificationFactory, staticObjects) {
            var ctx = this;

            $scope['newsAdd'] = ctx;

            ctx.$scope = $scope;
            ctx.$http = $http;
            ctx.$q = $q;
            ctx.$location = $location;
            ctx.newsAvailabilityService = NewsAvailabilityService;
            ctx.newsCategoryService = NewsCategoryService;
            ctx.newsRegionService = NewsRegionService;
            ctx.newsService = NewsService;
            ctx.newsStatusService = NewsStatusService;
            ctx.notificationFactory = notificationFactory;
            ctx.staticObjects = staticObjects;

            ctx.newsData = new NewsDto();
            ctx.newsData.availableFor = 1;


            // load all required data
            var loadPromise: ng.IPromise<{}> = ctx.load();

            // notify parents that the controller was created
            $scope.$emit('newsAdd.created', ctx);
        }


        // load all required info
        private load(): ng.IPromise<{}> {
            var ctx = this;

            ctx.isLoading = true;

            // populate news availabilities
            var newsAvailabilitiesPromise = ctx.populateNewsAvailabilities();
            // populate news categories
            var newsCategoriesPromise = ctx.populateNewsCategories();
            // populate news regions
            var newsRegionsPromise = ctx.populateNewsRegions();
            // populate news statuses
            var newsStatusesPromise = ctx.populateNewsStatuses();

            // create a promise based on all promises
            var allPromise = ctx.$q.all([newsAvailabilitiesPromise, newsCategoriesPromise, newsRegionsPromise, newsRegionsPromise, newsStatusesPromise]);

            allPromise.finally(function () {
                ctx.isLoading = false;
            });

            return allPromise;
        }


        // populate all news availabilities
        private populateNewsAvailabilities(): ng.IPromise<NewsAvailability[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsAvailability[]> = ctx.newsAvailabilityService.getNewsAvailabilities();

            getPromise.then(function (newsAvailabilities: NewsAvailability[]) {
                ctx.newsAvailabilitiesDic = {};
                ctx.newsAvailabilities = newsAvailabilities;
                $(newsAvailabilities).each(function () { ctx.newsAvailabilitiesDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news categories
        private populateNewsCategories(): ng.IPromise<NewsCategory[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsCategory[]> = ctx.newsCategoryService.getNewsCategories();

            getPromise.then(function (newsCategories: NewsCategory[]) {
                ctx.newsCategoriesDic = {};
                ctx.newsCategories = newsCategories;
                $(newsCategories).each(function () { ctx.newsCategoriesDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news regions
        private populateNewsRegions(): ng.IPromise<NewsRegion[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsRegion[]> = ctx.newsRegionService.getNewsRegions();

            getPromise.then(function (newsRegions: NewsRegion[]) {
                ctx.newsRegionsDic = {};
                ctx.newsRegions = newsRegions;
                $(newsRegions).each(function () { ctx.newsRegionsDic[this.id] = this; });
            });

            return getPromise;
        }

        // populate all news statuses
        private populateNewsStatuses(): ng.IPromise<NewsStatus[]> {
            var ctx = this;

            var getPromise: ng.IPromise<NewsStatus[]> = ctx.newsStatusService.getNewsStatuses();

            getPromise.then(function (newsStatuses: NewsStatus[]) {
                ctx.newsStatusesDic = {};
                ctx.newsStatuses = newsStatuses;
                $(newsStatuses).each(function () { ctx.newsStatusesDic[this.id] = this; });
            });

            return getPromise;
        }


        public toggleIsDateCreatedOpened($event) {
            $event.preventDefault();
            $event.stopPropagation();
            this.isDateCreatedOpened = !this.isDateCreatedOpened;
        }

        public toggleIsUnpublishedDateOpened($event) {
            $event.preventDefault();
            $event.stopPropagation();
            this.isUnpublishedDateOpened = !this.isUnpublishedDateOpened;
        }


        // publish news
        public publish(): ng.IPromise<NewsDto> {
            var ctx = this;

            // check if the form is valid
            if (ctx.$scope['newsAddForm'].$invalid || !ctx.IsValidDateRange() || ctx.IsBodyValid() != null) {
                ctx.showValidationMessages();
                return;
            }

            // set status to published
            ctx.newsData.status = 1;

            var publishPromise: ng.IPromise<NewsDto> = ctx.newsService.addNews(ctx.newsData);

            publishPromise.then(
                // success
                function (news: NewsDto) {
                    ctx.notificationFactory.success('News was published.');
                    ctx.$location.path('/news');
                },
                // error
                function () {
                    // set status to draft
                    ctx.newsData.status = 3;
                });

            return publishPromise;
        }

        // save current news
        public saveAndContinue(): ng.IPromise<NewsDto> {
            var ctx = this;

            // check if the form is valid
            if (ctx.$scope['newsAddForm'].$invalid || !ctx.IsValidDateRange() || ctx.IsBodyValid() != null) {
                ctx.showValidationMessages();
                return;
            }

            // set status to draft
            ctx.newsData.status = 3;

            var addPromise: ng.IPromise<NewsDto> = ctx.newsService.addNews(ctx.newsData);

            addPromise.then(
                // success
                function (news: NewsDto) {
                    ctx.notificationFactory.success('Saving complete.');
                    ctx.$location.path('/news');
                });

            return addPromise;
        }

        // cancel current edit
        public cancel(): ng.IPromise<{}> {
            var ctx = this;
            var def = ctx.$q.defer();

            if (!confirm('Are you sure you want to leave this page?')) {
                def.resolve();
                return def.promise;
            }

            // notify operation cancelled
            ctx.$location.path('/news');

            def.resolve();
            return def.promise;
        }

        // show validation messages
        public showValidationMessages() {
            var ctx = this;
            console.log(ctx.$scope['newsAddForm']);
            var form = ctx.$scope['newsAddForm'];
            var newsCategory = form['newsCategory'];
            var newsTitle = form['newsTitle'];
            var newsDateCreated = form['newsDateCreated'];
            var newsRegion = form['newsRegion'];
            var newsUnpublishedDate = form['newsUnpublishedDate'];
            var newsBody = form['newsBody'];

            // Category
            //if (newsCategory['$invalid']) {
            //    if (newsCategory['$error']['required'])
            //        ctx.showErrorCode(2003);

            //    return;
            //}

            // Title
            var titleMissing = false;

            if (newsTitle['$invalid']) {
                if (newsTitle['$error']['required'])
                    titleMissing = true;
                else
                    if (newsTitle['$error']['maxlength'])
                        ctx.showErrorCode(2005);

                //return;
            }

            var dateMissing = false;;
            // DateCreated
            if (newsDateCreated['$invalid'] && !newsDateCreated['$viewValue']) {
                if (newsDateCreated['$error']['required'])
                    dateMissing = true;
                else
                    ctx.showErrorCode(2007);
                //return;
            }

            var regionMissing = false;
            // Region
            if (newsRegion['$invalid']) {
                if (newsRegion['$error']['required'])
                    regionMissing = true;
                //return;
            }

            var unpublishDateMissing = false;
            // UnpublishedDate
            if (newsUnpublishedDate['$invalid'] && !newsUnpublishedDate['$viewValue']) {
                if (newsUnpublishedDate['$error']['required'])
                    unpublishDateMissing = true;
                else
                    ctx.showErrorCode(2008);
                //return;
            }

            //valid date range
            if (!ctx.IsValidDateRange()) {
                var dateRangeMessage = "Unpublished date must be bigger than date";
                ctx.notificationFactory.error('', dateRangeMessage);
            }

            var bodyMissing = false;
            // Body
            var isBodyError = ctx.IsBodyValid();
            if (isBodyError == 2111) {
                bodyMissing = true;
                //return;
            }

            var message = "Please check the following field(s): ";
            if (titleMissing)
                message += "<br/>Article title"
            if (dateMissing)
                message += "<br/>Date"
            if (regionMissing)
                message += "<br/>Region"
            if (unpublishDateMissing)
                message += "<br/>Unpublished date"
            if (bodyMissing)
                message += "<br/>Body"

            if (titleMissing || dateMissing || regionMissing || unpublishDateMissing || bodyMissing)
                ctx.notificationFactory.error('', message);
        }

        private IsBodyValid(): number {
            var ctx = this;

            var newText = $("#newsBody").text().replace("H1H2H3Toggle HTML", "");
            newText = newText.replace("\n", "");
            newText = newText.trim();

            if (newText.length == 0) {
                return 2111;
            }

            //if (newText.length > 5000) {
            //    return 2112;
            //}
            return null;
        }


        private IsValidDateRange(): boolean {

            var ctx = this;

            var p = new Date(Date.parse(ctx.newsData.dateCreated));
            var u = new Date(Date.parse(ctx.newsData.unpublishedDate));
            var pDate = new Date(p.getFullYear(), p.getMonth(), p.getDate());
            var upDate = new Date(u.getFullYear(), u.getMonth(), u.getDate());

            return upDate.getTime() >= (pDate.getTime() + (24 * 60 * 60 * 1000));
        }

        // show error code
        // TO DO: staticObjects has dependency on notificationFactory but notificationFactory is used to send messages
        // notificationFactory should use staticObjects to write messages based on provided codes which messages can be located into staticObjects.
        // In this case we cannot do cyclic references and therefore this method was created.
        private showErrorCode(code: number) {
            var ctx = this;
            var msg = ctx.staticObjects.getMessageByInternalCode(code);
            ctx.notificationFactory.error('', msg);
        }
    }

    // register controller with News Angular module
    angular.module('Sustainalytics.News').controller('NewsAddController', function ($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, $http: ng.IHttpService, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory: INotificationFactory, staticObjects: IStaticObjects) {
        var ctrl = new NewsAddController($scope, $q, $location, $http, NewsAvailabilityService, NewsCategoryService, NewsRegionService, NewsService, NewsStatusService, notificationFactory, staticObjects);
        return ctrl;
    });
}